﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using oAuth;
using Logic;
using BLL;
using DotNetOpenAuth.OpenId.RelyingParty;
using DotNetOpenAuth.OpenId;
using DotNetOpenAuth.OpenId.Extensions.AttributeExchange;
using System.Web.Security;
using Logic.ClarizenSvc;

namespace ClarizenGadget.Controllers
{
    public class OauthController : Controller
    {
        public static String TokenKey = "access_token";

        public ActionResult Oauth()
        {
            oAuthClarizen oAuth = oAuthClarizen.Get();
            var authorizeLink = oAuth.AuthorizationLinkGet(goTo: ClarizenUtils.GetGoTo());
            return Redirect(authorizeLink);
        }

        public ActionResult Callback()
        {
            ViewBag.Goto = ClarizenUtils.GetGoTo();
            
            oAuthClarizen oAuth = oAuthClarizen.Get();
            oAuth.AccessTokenGet();
            var session = oAuth.GetSessionKey();

            var remoteUser = new QueryComponent(session).GetCurrentUser(new BO.User());

            // get googleID and user from data base if logging in through google
            // TODO: when getting clarizen userID is available user userID to identify users
            var id = Users.GetGoogleID(useValidatedSig:false, useSession:true);
            var openID = false;
            BO.User user = Users.Get().Where(Users.Columns.ClarizenUserID, Actions.Equal, remoteUser.ID.Value).SelectOne();
            if (!String.IsNullOrEmpty(id))
            {
                openID = id[0] == '<';
                if (openID)
                    id = id.Substring(1);
            }
            
            //create/update user
            if (user == null)
            {
                user = new BO.User { Token = oAuth.Token, ClarizenSession = session, GoogleID = id, ClarizenUserID = remoteUser.ID.Value, UserName = remoteUser.DisplayName };
                user.Insert();
            }
            else
            {
                user.Token = oAuth.Token;
                user.ClarizenSession = session;
                user.Update();
            }

            BLL.Users.EnsureSession(user);
            
            if (!string.IsNullOrEmpty(oAuth.Token))
            {
                Session[TokenKey] = oAuth.Token;
            }

            if (openID)
                return new ClarizenController().Link("https://app.clarizen.com/Clarizen/default.aspx");
            else
            {
                ViewBag.Token = Users.CurrentUserID.HasValue ? HttpUtility.UrlEncode(BLL.Encryption.Encrypt(Users.CurrentUserID.ToString())) : "";
                return View();
            }
        }

        [HttpPost]
        public ActionResult AccessToken()
        {
            return Json(new GadgetResponse<Object> { Data = new { Token = Users.CurrentUserID.HasValue? HttpUtility.UrlEncode(BLL.Encryption.Encrypt(Users.CurrentUserID.ToString())): "", IsLoggedIn = new QueryComponent().IsLoggedIn }, Status = GadgetResponseStatus.Success });
        }

        public ActionResult OpenID(Boolean logout = false)
        {
            HostMetaDiscoveryService googleAppsDiscovery = new HostMetaDiscoveryService
            {
                UseGoogleHostedHostMeta = true,
            };

            relyingParty = new OpenIdRelyingParty();
            relyingParty.DiscoveryServices.Insert(0, googleAppsDiscovery);

            
            IAuthenticationResponse authResponse = relyingParty.GetResponse();
            if (authResponse != null)
            {
                var q = new Uri(authResponse.ClaimedIdentifier).Query;
                var googleID =  HttpUtility.ParseQueryString(q)["id"];
                
                switch (authResponse.Status)
                {
                    case AuthenticationStatus.Authenticated:
                        var user = BLL.Users.Get()
                                            .Where(Users.Columns.GoogleID, Actions.Equal, googleID)
                                            .SelectOne();

                        if (user != null && logout)
                        {
                            user.Delete();
                            user = null;
                        }

                        if (user != null && user.Token != null && Users.EnsureSession(user, true))
                        {

                            AppLoginMessage msg = new AppLoginMessage { };
                            var res = (AppLoginResult)new QueryComponent().Execute(msg)[0];
                            return Redirect(string.Format("{1}&targetUrl={0}", HttpUtility.UrlEncode("https://app.clarizen.com/Clarizen/default.aspx"), res.Url));
                        }
                        else
                        {
                            Session[Logic.Constants.googleID] = "<" + googleID;
                            return Redirect(Logic.Constants.CurrentUrl + "/Clarizen/Create");
                        }
                        break;
                        //FetchResponse fetch = authResponse.GetExtension<FetchResponse>();
                        //if (fetch != null)
                        //{
                        //    // Save user details in session variables
                        //    Session["email"] = fetch.GetAttributeValue(WellKnownAttributes.Contact.Email);
                        //    Session["firstName"] = fetch.GetAttributeValue(WellKnownAttributes.Name.First);
                        //    Session["lastName"] = fetch.GetAttributeValue(WellKnownAttributes.Name.Last);
                        //}

                        //// Set the authentication cookie for the user
                        //FormsAuthentication.SetAuthCookie(authResponse.ClaimedIdentifier, false);
                    case AuthenticationStatus.Canceled:
                    case AuthenticationStatus.Failed:
                    default:
                        return RedirectToAction("Login", "Login");
                }
            }
            else if (Request["domain"] != null)
            {
                IAuthenticationRequest request = relyingParty.CreateRequest(Request["domain"]);
                sendGoogleRequest(request);
                return null;
            }

            return null;
        }

        private void sendGoogleRequest(IAuthenticationRequest request)
        {
            // Request access to e-mail address, first name and last name
            // via OpenID Attribute Exchange (AX)
            FetchRequest fetch = new FetchRequest();
            fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Contact.Email, true));
            fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.First, true));
            fetch.Attributes.Add(new AttributeRequest(WellKnownAttributes.Name.Last, true));
            request.AddExtension(fetch);

            // Send your visitor to their Provider for authentication.  
            request.RedirectToProvider();
        }

        //protected void loginButton_Click(object sender, EventArgs e)
        //{
        //    IAuthenticationRequest request = relyingParty.CreateRequest(openIdBox.Text);
        //    sendGoogleRequest(request);
        //}

        private OpenIdRelyingParty relyingParty;
    }
}
